//
// Created by chizuru on 2025/9/2.
//
#include <string>
#include "TinyXmlRegisterCLBMap.h"
#include "CameraController.h"
#include "RegisterReadCommand.h"
#include "TransactionCommandBatchRead.h"

using std::shared_ptr;
using std::pair;
using std::tuple;
using std::string;
using std::nullopt;
using std::optional;
using std::vector;

CameraController::CameraController(CameraDevice &c, shared_ptr<TinyXmlRegisterCLBMap> rm, RetryPolicy rp)
        : comm(c)
        , regMap(rm)
        , rp(rp) {
}

OperationResult CameraController::setRegister(const std::string &cat, const std::string &name, uint32_t value, bool isRollback) {
    auto addrOpt = regMap->getAddress(cat, name);
    if (!addrOpt) {
        return OperationResult::Fail(ErrorCode::InvalidAddress, "Invalid register");
    }

    RegisterWriteCommand wcmd(comm, *addrOpt, value, rp, isRollback);   /* 回滚则需要记录原值 */
    if (!wcmd.execute()) {
        if (isRollback) {
            if (!wcmd.undo()) {
                return OperationResult::Fail(ErrorCode::RollbackFailure, "Failed to write to the register, and failed to roll back");
            }
            return OperationResult::Fail(ErrorCode::WriteFailure, "Failed to write to the register, but rollback succeeded");
        }
        return OperationResult::Fail(ErrorCode::WriteFailure, "Write to register failed");
    }
    return OperationResult::Ok("Successfully written to register");
}

OperationResult CameraController::getRegister(const std::string &cat, const std::string &name, std::optional<uint32_t> &out) {
    auto addrOpt = regMap->getAddress(cat, name);
    if (!addrOpt) {
        return {false, ErrorCode::InvalidAddress, "Invalid register"};
    }

    uint32_t outPtr;
    RegisterReadCommand rcmd(comm, *addrOpt, &outPtr, rp);
    if (!rcmd.execute()) {
        return {false, ErrorCode::ReadFailure, "Read register failed"};
    }

    out = outPtr;
    return {true, ErrorCode::OK, "Read register successfully"};
}


OperationResult CameraController::applyTransactionWrite(const vector<tuple<string, string, uint32_t>> &ops) {
    vector<pair<uint16_t, uint32_t>> writes;
    for (auto &t: ops) {
        auto addrOpt = regMap->getAddress(get<0>(t), get<1>(t));
        if (!addrOpt) {
            std::string eStr = "Unknown reg " + get<0>(t) + "." + get<1>(t) + "\n";
            return {false, ErrorCode::InvalidAddress, eStr};
        }
        writes.push_back({*addrOpt, get<2>(t)});
    }
    TransactionCommandBatchWrite tc(comm, writes, rp);
    return tc.execute();
}

OperationResult CameraController::applyTransactionRead(const vector<std::pair<std::string, std::string>> &ops, std::vector<std::optional<uint32_t>>& out) {
    vector<pair<uint16_t, uint32_t>> reads;
    for (auto &t: ops) {
        auto addrOpt = regMap->getAddress(t.first, t.second);
        if (!addrOpt) {
            std::string eStr = "Unknown reg " + get<0>(t) + "." + get<1>(t) + "\n";
            return {false, ErrorCode::InvalidAddress, eStr};
        }
        reads.push_back({*addrOpt, {}});
    }
    TransactionCommandBatchRead tc(comm, reads, rp);

    auto r = tc.execute();
    if (!r.success){
        return r;
    }

    for (auto& [addr, value]: reads) {
        out.push_back(value);
    }
    return r;
}
